Repository navigation
Fix #201: re-fold the HRV baseline on a window switch instead of restarting calibration - #207
Closed
digitalerdude wants to merge 1 commit into
Closed
digitalerdude wants to merge 1 commit into
digitalerdude wants to merge 1 commit into
Conversation
…f restarting calibration Switching the HRV window (Whole-night ↔ Deep-sleep) re-anchored the HRV baseline epoch to now, which drops all history and restarts the ≥4-night calibration — so a user with plenty of nights fell back to "calibrating" for several nights and Charge went nil. That read as "the deep-sleep setting is broken" (ryanbr#195). analyzeRecent already re-scores the recent ~21 nights' avgHrv under the new window AND re-folds the HRV baseline from them in the same pass, and the baseline's 14-night-half-life EWMA is dominated by that fresh re-scored tail. So the epoch reset is unnecessary: drop it from both window-switch handlers (SettingsView / SettingsScreen), keep the forced re-score. An established user (≥ minNightsSeed valid nights) now sees the switch take effect immediately; a genuine cold-start user still calibrates honestly. The manual "Recalibrate Charge baseline" button is untouched — it still resets both epochs on purpose. Updates the picker copy + Android toast to match, and adds a pure fold regression test on both platforms (Swift BaselinesTests + Android HrvBaselineRecalibrationTest) pinning that re-scored new-window nights fold to a usable baseline WITHOUT an epoch reset. Verification: swift test (StrandAnalytics BaselinesTests, 22/22) green; Strand macOS app target compiles (app-build CI is disabled). Android JVM test mirrors the Swift one but wasn't run locally (no Android SDK). HRV baseline behaviour across several nights still needs on-device confirmation, per the issue. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
|
Thanks — reviewed and landed on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #195 / implements #201.
Problem
Switching the HRV window (Whole-night ↔ Deep-sleep) in Settings re-anchored the HRV baseline epoch to
now. That drops all history and restarts the ≥4-night calibration, so a user with plenty of nights fell back to "calibrating" for several nights and Charge wentnilScore. That reads as "the deep-sleep setting is broken" (#195).Why the reset is unnecessary
The same handler already forces a re-score, and
analyzeRecent:avgHrvunder the new window, deterministically from stored R-R, andbaselines2).The HRV baseline is a 14-night-half-life EWMA (
Baselines.metricCfg["hrv"]), so it's dominated by that fresh, just-re-scored tail. A plain re-score therefore already lands the baseline on the new window for anyone with ≥minNightsSeedvalid nights — no artificial calibration reset needed.Change
hrvBaselineEpoch = nowwrite from both window-switch handlers (Strand/Screens/SettingsView.swift,android/.../ui/SettingsScreen.kt); keep the forced re-score (Android also keeps theanalyzeWatermarkclear so the re-score runs even though the raw HR fingerprint is unchanged).Parity & scope
minNightsSeedvalid nights) still calibrates honestly — expected, per the issue.Verification
swift test—StrandAnalyticsBaselinesTests22/22 green, including the newtestWindowSwitchRefoldStaysUsableWithoutEpochReset.StrandmacOS app target compiles (app-build.ymlis disabled, so app-target Swift has no default CI).HrvBaselineRecalibrationTest.windowSwitchRefold_staysUsableWithoutEpochReset) mirroring the Swift one; not run locally (no Android SDK) — relying onandroid.yml.🤖 Generated with Claude Code